package system

import (
	"context"
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"server/internal/consts"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
)

type sSystemUser struct {
}

func init() {
	service.RegisterSystemUser(&sSystemUser{})
}

func (s *sSystemUser) Create(ctx context.Context, in model.SystemUserCreateInput) (id int64, err error) {
	if err = s.checkUserIsRepeat(ctx, in.Username, 0); err != nil {
		return 0, err
	}
	err = dao.SystemUser.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		adminID := service.SystemLogin().GetAdminID(ctx)

		//添加用户
		id, err = tx.Ctx(ctx).InsertAndGetId(dao.SystemUser.Table(), do.SystemUser{
			Username:  in.Username,
			Password:  s.DefaultPassword(),
			Name:      in.Name,
			Avatar:    in.Avatar,
			Phone:     in.Phone,
			CreatedBy: adminID,
		})
		if err != nil {
			return err
		}
		if len(in.RoleIds) > 0 {
			roleUsers := make([]do.SystemRoleUser, 0, len(in.RoleIds))
			for _, roleId := range in.RoleIds {
				roleUsers = append(roleUsers, do.SystemRoleUser{
					UserId:    id,
					RoleId:    roleId,
					CreatedBy: adminID,
				})
			}
			if _, err = tx.Ctx(ctx).Insert(dao.SystemRoleUser.Table(), roleUsers); err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return 0, err
	}
	return id, nil
}

func (s *sSystemUser) checkUserIsRepeat(ctx context.Context, username string, id int64) error {
	where := g.Map{
		"username": username,
	}
	if id > 0 {
		where["id <> ?"] = id
	}
	count, err := dao.SystemUser.Ctx(ctx).Where(where).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return gerror.New("用户名 重复")
	}
	return nil
}

// EncryptPassword 密码加密 password 为md5值
func (s *sSystemUser) EncryptPassword(password string) (string, error) {
	result, err := gmd5.EncryptString(password)
	if err != nil {
		return "", err
	}
	return result, nil
}

func (s *sSystemUser) UpdateById(ctx context.Context, userId int64, in model.SystemUserUpdateInput) (err error) {
	if err = s.checkUserIsRepeat(ctx, in.Username, userId); err != nil {
		return err
	}

	err = dao.SystemUser.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		adminID := service.SystemLogin().GetAdminID(ctx)

		//删除关联的角色
		_, err = tx.Ctx(ctx).Update(dao.SystemRoleUser.Table(), do.SystemRoleUser{
			DeletedAt: gtime.Now(),
			DeletedBy: adminID,
		}, do.SystemRoleUser{
			UserId: userId,
		})
		if err != nil {
			return err
		}

		//修改用户信息
		_, err = tx.Ctx(ctx).Update(dao.SystemUser.Table(), do.SystemUser{
			Username:  in.Username,
			Name:      in.Name,
			Avatar:    in.Avatar,
			Phone:     in.Phone,
			UpdatedBy: adminID,
		}, do.SystemUser{
			Id: userId,
		})
		if err != nil {
			return err
		}

		//添加新的角色关联
		if len(in.RoleIds) > 0 {
			roleUsers := make([]do.SystemRoleUser, 0, len(in.RoleIds))
			for _, roleId := range in.RoleIds {
				roleUsers = append(roleUsers, do.SystemRoleUser{
					UserId:    userId,
					RoleId:    roleId,
					CreatedBy: adminID,
				})
			}
			if _, err = tx.Ctx(ctx).Insert(dao.SystemRoleUser.Table(), roleUsers); err != nil {
				return err
			}
		}
		return nil
	})

	if err != nil {
		return err
	}

	service.SystemAuthorityCache().RemoveUserPermissionLastUpdatedTime(ctx, userId)

	return nil
}

func (s *sSystemUser) DeleteById(ctx context.Context, id int64) (err error) {
	_, err = dao.SystemUser.Ctx(ctx).Data(do.SystemUser{
		DeletedBy: service.SystemLogin().GetAdminID(ctx),
		DeletedAt: gtime.Now(),
	}).Where(do.SystemUser{Id: id}).Update()
	if err != nil {
		return err
	}
	return nil
}

func (s *sSystemUser) List(ctx context.Context, in model.SystemUserListInput) (users []model.SystemUserListOutput, total int, err error) {
	users = make([]model.SystemUserListOutput, 0)
	total = 0
	err = nil

	where := g.Map{}
	if len(in.Keyword) > 0 {
		keywordStr := "%" + in.Keyword + "%"
		where["(username like ?) OR (name like ?)"] = []string{keywordStr, keywordStr}
	}
	if len(in.RoleIds) > 0 {
		tempUserIds, _ := s.getUserIdsByRoles(ctx, in.RoleIds)
		if len(tempUserIds) > 0 {
			where["id in (?)"] = tempUserIds
		} else {
			return
		}
	}
	if len(in.Phone) > 0 {
		where["phone"] = in.Phone
	}
	if len(in.Username) > 0 {
		where["username like ?"] = "%" + in.Username + "%"
	}

	err = dao.SystemUser.Ctx(ctx).
		Where(where).
		Page(in.Page, in.PageSize).
		ScanAndCount(&users, &total, true)

	//查询关联的角色
	if len(users) > 0 {
		err = dao.SystemRole.Ctx(ctx).As("r").
			InnerJoin("system_role_user ru", "ru.role_id = r.id").
			Fields("r.*,ru.user_id").
			WhereIn("ru.user_id", gdb.ListItemValuesUnique(users, "Id")).
			ScanList(&users, "Roles", "user_id:id") //id=users.id  user_id=ru.userid
	}

	return
}

func (s *sSystemUser) getUserIdsByRoles(ctx context.Context, roleIds []int) (userIds []interface{}, err error) {
	userIds = make([]interface{}, 0)
	tempUsers := make([]entity.SystemRoleUser, 0)
	err = dao.SystemRoleUser.Ctx(ctx).As("ru").
		InnerJoin("system_role r", "ru.role_id = r.id").
		Fields("distinct ru.user_id").
		Where(g.Map{"ru.user_id in (?)": roleIds}).Scan(&tempUsers)
	if err != nil {
		return
	}
	userIds = gdb.ListItemValuesUnique(tempUsers, "UserId")
	return userIds, err
}

func (s *sSystemUser) DefaultPassword() (p string) {
	// 读取配置的默认密码
	password, _ := service.SystemConfig().GetContentByCode(gctx.GetInitCtx(), consts.ConfigCodeBaseSystemUserDefaultPassword)
	if len(password) == 0 {
		password = "Abc0727."
	}

	// 对密码先进行md5加密：前端传的值也是md5
	password, _ = gmd5.EncryptString(password)

	p, _ = s.EncryptPassword(password)

	return p
}

func (s *sSystemUser) ResetPassword(ctx context.Context, id int64) (err error) {
	_, err = dao.SystemUser.Ctx(ctx).Data(do.SystemUser{
		Password:  s.DefaultPassword(),
		UpdatedBy: service.SystemLogin().GetAdminID(ctx),
	}).Where(do.SystemUser{Id: id}).Update()
	return err
}

func (s *sSystemUser) ChangePassword(ctx context.Context, id int64, password string) (err error) {
	newPassword, _ := s.EncryptPassword(password)
	_, err = dao.SystemUser.Ctx(ctx).Data(do.SystemUser{
		Password:  newPassword,
		UpdatedBy: service.SystemLogin().GetAdminID(ctx),
	}).Where(do.SystemUser{Id: id}).Update()
	return err
}

func (s *sSystemUser) UpdateUserById(ctx context.Context, userId int64, in model.SystemUserUpdateInput) (err error) {
	//修改用户信息
	_, err = dao.SystemUser.Ctx(ctx).Data(do.SystemUser{
		Name:      in.Name,
		Avatar:    in.Avatar,
		Phone:     in.Phone,
		UpdatedBy: service.SystemLogin().GetAdminID(ctx),
	}).Where(do.SystemUser{Id: userId}).Update()
	return err
}

func (s *sSystemUser) GetOneByID(ctx context.Context, ID int64) (adminInfo *entity.SystemUser, err error) {
	adminInfo = new(entity.SystemUser)
	err = dao.SystemUser.Ctx(ctx).Where(do.SystemUser{Id: ID}).Scan(adminInfo)
	return
}
